Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CRYPTO-169] Add protection for the ExceptionInInitializerError scenario to the CryptoRandomFactory#getCryptoRandom(Properties) method #258

Merged
merged 6 commits into from
Oct 22, 2023

Conversation

LuciferYang
Copy link
Contributor

In version 1.2.0 of commons-crypto, the static initialization code block of o.a.c.crypto.random.OpenSslCryptoRandom may throw a GeneralSecurityException wrapped by IllegalStateException, which ultimately gets wrapped into j.l.ExceptionInInitializerError by Java's own mechanism.

This results in behavior differences when running the statement

org.apache.commons.crypto.random.CryptoRandomFactory#getCryptoRandom(new java.util.Properties());

on platforms that do not support OpenSslCryptoRandom compared to when using commons-crypto 1.1.0 (e.g. Apple Silicon)

  • commons-crypto 1.1.0

After OpenSslCryptoRandom initialization fails, it tries to initialize JavaCryptoRandom, and JavaCryptoRandom can be successfully initialized and return results.

  • commons-crypto 1.2.0

After OpenSslCryptoRandom initialization fails, it throws an ExceptionInInitializerError. Since the CryptoRandomFactory#getCryptoRandom method does not catch ExceptionInInitializerError and perform fault tolerance, ExceptionInInitializerError continues to be thrown upward, losing the opportunity to try to initialize JavaCryptoRandom.

Therefore, this PR adds the catch and fault tolerance for ExceptionInInitializerError in the CryptoRandomFactory#getCryptoRandom method to keep it behaving similarly to commons-crypto 1.1.0.

@codecov-commenter
Copy link

codecov-commenter commented Oct 22, 2023

Codecov Report

Merging #258 (1c206a8) into master (c5d19d0) will decrease coverage by 0.03%.
Report is 1 commits behind head on master.
The diff coverage is 66.66%.

@@             Coverage Diff              @@
##             master     #258      +/-   ##
============================================
- Coverage     74.69%   74.66%   -0.03%     
  Complexity      441      441              
============================================
  Files            38       38              
  Lines          1810     1816       +6     
  Branches        176      177       +1     
============================================
+ Hits           1352     1356       +4     
- Misses          348      349       +1     
- Partials        110      111       +1     
Files Coverage Δ
...che/commons/crypto/random/CryptoRandomFactory.java 90.00% <66.66%> (-3.19%) ⬇️

📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more

@@ -141,4 +141,14 @@ public void testNull() {
assertThrows(NullPointerException.class, () -> CryptoRandomFactory.getCryptoRandom(null));
}

@Test
public void testExceptionInInitializerErrorRandom() throws GeneralSecurityException, IOException {
Copy link
Contributor Author

@LuciferYang LuciferYang Oct 22, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there are no chagnes to CryptoRandomFactory.java, the new test case will fail:

java.lang.ExceptionInInitializerError
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:534)
	at java.base/java.lang.Class.forName(Class.java:513)
	at org.apache.commons.crypto.utils.ReflectionUtils.getClassByNameOrNull(ReflectionUtils.java:93)
	at org.apache.commons.crypto.utils.ReflectionUtils.getClassByName(ReflectionUtils.java:64)
	at org.apache.commons.crypto.random.CryptoRandomFactory.getCryptoRandom(CryptoRandomFactory.java:189)
	at org.apache.commons.crypto.random.CryptoRandomFactoryTest.testExceptionInInitializerErrorRandom(CryptoRandomFactoryTest.java:150)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: java.lang.IllegalStateException: java.security.GeneralSecurityException: ExceptionInInitializerErrorRandom init failed
	at org.apache.commons.crypto.random.ExceptionInInitializerErrorRandom.<clinit>(ExceptionInInitializerErrorRandom.java:28)
	... 10 more
Caused by: java.security.GeneralSecurityException: ExceptionInInitializerErrorRandom init failed
	at org.apache.commons.crypto.random.ExceptionInInitializerErrorRandom.check(ExceptionInInitializerErrorRandom.java:33)
	at org.apache.commons.crypto.random.ExceptionInInitializerErrorRandom.<clinit>(ExceptionInInitializerErrorRandom.java:26)
	... 10 more

import java.io.IOException;
import java.security.GeneralSecurityException;

public class ExceptionInInitializerErrorRandom implements CryptoRandom {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class is used to simulate scenarios where OpenSslCryptoRandom fails in the static code block checkNative() or !OpenSslCryptoRandomNative.nextRandBytes(new byte[1]) is false.

@garydgregory
Copy link
Member

garydgregory commented Oct 22, 2023

@garydgregory garydgregory merged commit 7c61551 into apache:master Oct 22, 2023
13 checks passed
@LuciferYang
Copy link
Contributor Author

Thanks @garydgregory ~

garydgregory added a commit that referenced this pull request Oct 22, 2023
…rio to the CryptoRandomFactory#getCryptoRandom(Properties) method #258
@garydgregory
Copy link
Member

Thanks @garydgregory ~

YW! 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants